package com.study.mongo;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.study.configuer.SpringContextHolder;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import java.util.List;
import java.util.Map;


/**
 * @author ：ihao ∶）
 * @date ：Created in 2021-01-13 12:06
 */

public class MongoUtil {

    private static MongoTemplate mongoTemplate;

    /**
     * 获取资源
     *
     * @author 赖浩
     */
    private static void getResource() {
        if (mongoTemplate == null) {
            mongoTemplate = SpringContextHolder.getBean(MongoTemplate.class);
        }
    }

    /**
     * 保存数据
     *
     * @param object 对象
     * @return 插入的数据
     * @author 赖浩
     */
    public static <T> T save(T object) {
        getResource();
        return mongoTemplate.save(object);
    }

    /**
     * 根据model条件查询单条数据
     *
     * @param model  条件类
     * @param tClass 返回的实体类
     * @return 实例
     * @author 赖浩
     */
    public static <T> T findOneByModel(T model, Class<T> tClass, MongoSelectDTO mongoSelectDTO) {
        if (tClass == null || model == null) {
            return null;
        }
        Map<String, Object> map = BeanUtil.beanToMap(model, false, true);
        if (CollUtil.isNotEmpty(map)) {
            Criteria criteria = new Criteria();
            map.forEach((key, value) -> criteria.and(key).is(value));
            getResource();
            Query query = addSort(new Query(criteria), mongoSelectDTO);
            return mongoTemplate.findOne(query, tClass);
        }
        return null;
    }

    private static Query addSort(Query query, MongoSelectDTO mongoSelectDTO) {
        if (mongoSelectDTO == null) {
            query.skip(0).limit(100);
            return query;
        }
        if (mongoSelectDTO.getSortName() != null) {
            if (mongoSelectDTO.isDesc()) {
                query.with(Sort.by(Sort.Order.desc(mongoSelectDTO.getSortName())));
            } else {
                query.with(Sort.by(Sort.Order.asc(mongoSelectDTO.getSortName())));
            }
        }
        query.skip(mongoSelectDTO.getStart()).limit(mongoSelectDTO.getPageSize());
        return query;
    }

    /**
     * 根据model条件查询所有数据
     *
     * @param model  条件类
     * @param tClass 返回的实体类
     * @return 实例
     * @author 赖浩
     */
    public static <T> List<T> findAllByModel(T model, Class<T> tClass, MongoSelectDTO mongoSelectDTO) {
        if (tClass == null || model == null) {
            return null;
        }
        Map<String, Object> map = BeanUtil.beanToMap(model, false, true);
        if (CollUtil.isNotEmpty(map)) {
            Criteria criteria = new Criteria();
            map.forEach((key, value) -> criteria.and(key).is(value));
            getResource();
            Query query = addSort(new Query(criteria), mongoSelectDTO);
            return mongoTemplate.find(query, tClass);
        }
        return null;
    }

    /**
     * 修改单条 存在则更新不存在则插入
     *
     * @param selectModel 修改条件
     * @param updateModel 修改参数
     * @param tClass      类
     */
    public static void update(Object selectModel, Object updateModel, Class tClass) {
        Map<String, Object> map = BeanUtil.beanToMap(selectModel, false, true);
        Map<String, Object> updateMap = BeanUtil.beanToMap(updateModel, false, true);
        if (CollUtil.isNotEmpty(map)) {
            return;
        }
        // 修改数据
        Update update = new Update();
        updateMap.forEach(update::set);
        // 修改条件
        Criteria criteria = new Criteria();
        map.forEach((key, value) -> criteria.and(key).is(value));
        //存在修改，不存在新增
        mongoTemplate.upsert(new Query(criteria), update, tClass);
    }

    /**
     * 修改多条
     *
     * @param selectModel 修改条件
     * @param updateModel 修改参数
     * @param tClass      类
     */
    public static void updateMulti(Object selectModel, Object updateModel, Class tClass) {
        Map<String, Object> map = BeanUtil.beanToMap(selectModel, false, true);
        Map<String, Object> updateMap = BeanUtil.beanToMap(updateModel, false, true);
        if (CollUtil.isEmpty(map)) {
            return;
        }
        // 修改数据
        Update update = new Update();
        updateMap.forEach(update::set);
        // 修改条件
        Criteria criteria = new Criteria();
        map.forEach((key, value) -> criteria.and(key).is(value));
        //存在修改，不存在新增
        mongoTemplate.updateMulti(new Query(criteria), update, tClass);
    }

    /**
     * 查询总数
     *
     * @param object 修改条件
     * @param tClass 类
     * @return 总数
     */
    public static <T> long findCount(T object, Class<T> tClass) {
        Map<String, Object> map = BeanUtil.beanToMap(object, false, true);
        if (CollUtil.isEmpty(map)) {
            return 0;
        }
        // 修改条件
        Criteria criteria = new Criteria();
        map.forEach((key, value) -> criteria.and(key).is(value));
        //存在修改，不存在新增
        return mongoTemplate.count(new Query(criteria), tClass);
    }
}
